package chat

import (
	"encoding/binary"
	"errors"
	"io"
	"log"
	"net"

	netpack "im/im_server/proto"

	"google.golang.org/protobuf/proto"
)

const (
	PacketLen = 65536
)

type Connection struct {
	conn   net.Conn
	send   chan []byte
	player *Player
}

func (c *Connection) output() {
	defer c.close()
	for m := range c.send {
		err := binary.Write(c.conn, binary.BigEndian, int32(len(m)))
		if err != nil {
			log.Println(err)
			break
		}

		var n int
		n, err = c.conn.Write(m)
		if err != nil {
			log.Println(err)
			break
		}

		if n != len(m) {
			log.Println("short wirte")
			break
		}
	}
}

func (c *Connection) kick() {
	log.Println("kick connection")
	c.player.PlayerId = -1
	c.conn.Close()
}

func (c *Connection) close() {
	log.Println("close connection")
	c.conn.Close()
}

func (c *Connection) replyError(err error) {
	scError := &netpack.ErrorMessage{}
	scError.Error = err.Error()
	c.reply(netpack.MessageID_SC_ERROR, scError)
}

func (c *Connection) reply(id netpack.MessageID, m proto.Message) error {
	msg, err := proto.Marshal(m)
	if err != nil {
		return err
	}

	protocol := &netpack.Protocol{}
	protocol.Id = id
	protocol.Msg = msg

	replyData, err := proto.Marshal(protocol)
	if err != nil {
		return err
	}

	c.send <- replyData
	return nil
}

func (c *Connection) input() {
	for {
		message, err := c.readMessage()
		if err != nil {
			log.Println(err)
			break
		}

		err = c.player.handleMessageProcess(message, c)
		if err != nil {
			log.Println(err)
			c.replyError(err)
		}
	}
}

func (c *Connection) readMessage() (message []byte, err error) {
	var length int32
	err = binary.Read(c.conn, binary.BigEndian, &length)
	if err != nil {
		return nil, err
	}

	if length > PacketLen || length < 0 {
		return nil, errors.New("invalid length")
	}

	message = make([]byte, int(length))
	if length > 0 {
		var n int
		n, err = io.ReadFull(c.conn, message)
		if err != nil {
			return nil, err
		}

		if n != len(message) {
			return message, errors.New("short read")
		}
	}
	return message, nil
}
